/*
 * @Author: hongbin
 * @Date: 2021-12-07 19:51:37
 * @LastEditors: hongbin
 * @LastEditTime: 2021-12-12 13:33:06
 * @Description: 音乐组件
 */
import Image from "next/image";
import {
  createRef,
  FC,
  ReactElement,
  useCallback,
  useEffect,
  useImperativeHandle,
  useRef,
  useState,
} from "react";
import styled, { css } from "styled-components";
import { getMusicInfo, IMusicInfo } from "../../api/music";
import { getImagePath } from "../../constant/url";
import { flexCenter } from "../BUI/styled";
import { ThemePrimaryBgc } from "../BUI/View/ThemeView";
import ControlBar from "./ControlBar";
import ProcessBar from "./ProcessBar";
import Volume from "./Volume";

interface IProps {}
// 暴露方法方便外面控制
export const MusicCardRef = createRef<{ toggleShow: () => void }>();

const MusicCard: FC<IProps> = (): ReactElement => {
  const [isShow, setIsShow] = useState(false); //是否显示面板
  const [musicInfo, setMusicInfo] = useState<Partial<IMusicInfo>>({});
  const [isPlay, setIsPlay] = useState(false); //是否播放
  const [volume, setVolume] = useState(0); //音量
  const musicRef = useRef<HTMLAudioElement>(null);
  const prevState = useRef({ volume: 0, duration: 0 });

  useEffect(() => {
    const music = musicRef.current;
    if (!music) return;
    if (isShow) {
      const progressVal = document.getElementById(
        "music_card_progress_val"
      ) as HTMLDivElement;
      const progressPoint = document.getElementById(
        "music_card_progress_point"
      ) as HTMLDivElement;
      const { duration } = prevState.current;

      const setProgress = (currentTime: number) => {
        const progress = (currentTime / duration) * 100;
        progressVal.style.width = progress + "%";

        if (!progressPoint.getAttribute("onDrag")) {
          progressPoint.style.left = progress + "%";
        }
      };

      setProgress(music.currentTime);

      music.ontimeupdate = e => {
        //@ts-ignore
        setProgress(e.target.currentTime);
      };
    } else {
      music.ontimeupdate = null;
    }
  }, [isShow]);

  useEffect(() => {
    getMusicInfo()
      .then(({ data }) => {
        console.log(data);
        if (data) {
          setMusicInfo(data);
          const audio = musicRef.current;
          if (!audio) return;
          setVolume(audio.volume);
          prevState.current = { ...prevState.current, volume: audio.volume };
        }
      })
      .catch(err => {
        console.error("获取音乐失败", err);
      });
  }, []);

  const setPlayState = (state: boolean) => {
    const audio = musicRef.current;
    if (!audio) return;
    // 用户未和document交互时无法播放
    if (state) audio.play();
    else audio.pause();
  };

  const toggleMute = (val?: number) => {
    const audio = musicRef.current;
    if (!audio) return;
    if (val) {
      // 指定值
      prevState.current = { ...prevState.current, volume: audio.volume };
      audio.volume = val;
      setVolume(val);
    } else if (audio.volume) {
      // 保存状态
      prevState.current = { ...prevState.current, volume: audio.volume };
      audio.volume = 0;
      setVolume(0);
    } else {
      const { volume = 0.5 } = prevState.current;
      audio.volume = volume;
      setVolume(volume);
    }
  };

  const handleChangePlayTime = (percent: number) => {
    const music = musicRef.current;
    if (music) {
      music.currentTime =
        music.currentTime + percent * prevState.current.duration;
    }
  };

  const toggleShow = useCallback(() => {
    setIsShow(state => !state);
  }, []);

  useImperativeHandle(
    MusicCardRef,
    () => ({
      toggleShow,
    }),
    [toggleShow]
  );

  return (
    <Container isShow={isShow}>
      <audio
        onCanPlay={e => {
          prevState.current = {
            ...prevState.current,
            // @ts-ignore
            duration: e.target.duration,
          };
          setPlayState(!isPlay);
        }}
        onEnded={e => {
          console.log("播放完毕", e);
          setIsPlay(false);
        }}
        ref={musicRef}
        src={musicInfo.link}
        onPlay={() => {
          setIsPlay(true);
        }}
        onPause={() => {
          setIsPlay(false);
        }}
      />
      <div>
        <Cover>
          <Image
            alt=""
            src={{
              src: `${getImagePath}${musicInfo.cover}`,
              width: 128,
              height: 128,
            }}
          />
        </Cover>
        <Content>
          <Desc>
            <p>{musicInfo.name}</p>
            <span>{musicInfo.desc}</span>
          </Desc>
          <ControlBar
            isPlay={isPlay}
            togglePlayState={() => setPlayState(!isPlay)}
          />
          <ProcessBar onChangePlayTime={handleChangePlayTime} />
        </Content>
        <Volume volume={volume} toggleMute={toggleMute} />
      </div>
    </Container>
  );
};

export default MusicCard;

const Desc = styled.div`
  text-align: center;
  p {
    margin-bottom: 0;
  }
  span {
    font-size: 0.7rem;
    display: block;
    color: #ccc;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 8rem;
    margin: 0 auto;
  }
`;

const Content = styled.div`
  width: 10rem;
  height: 100%;
  display: flex;
  flex-direction: column;
  color: #fffae5;
  letter-spacing: 1px;
`;

const Cover = styled.div`
  width: 8rem;
  height: 8rem;
  background: #ffffff77;
  border-radius: inherit;
  overflow: hidden;
  img {
    width: 8rem;
    height: 8rem;
  }
`;

const Container = styled.div<{ isShow?: boolean }>`
  height: 10rem;
  width: 22rem;
  position: absolute;
  top: 4.5rem;
  transition-property: transform, opacity;
  transition-duration: 0.3s, 0.4s;
  transform-origin: left;
  transform: translateY(-100px) scale(0);
  margin: 0;
  opacity: 0;
  cursor: default;
  svg {
    fill: #fffae5;
  }

  @media (max-width: ${props => props.theme.media.phone}) {
    left: 50%;
    ${({ isShow }) =>
      isShow &&
      css`
        transform: translateY(0) scale(1) translateX(-50%);
        opacity: 1;
      `}
  }

  ${({ isShow }) =>
    isShow &&
    css`
      transform: translateY(0) scale(1);
      opacity: 1;
    `}

  & > div {
    border-radius: 5px;
    position: relative;
    width: 100%;
    height: 100%;
    ${ThemePrimaryBgc};
    ${flexCenter};
    padding: 1rem;
    background: ${props =>
      props.theme.mode === "dark"
        ? "linear-gradient(170deg,#544c4c,#1e0062)"
        : "linear-gradient(170deg, #faa, #51f)"};
    box-shadow: 1px 1px 15px 0px #666;
  }
`;
